﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Objects.DataClasses;
using System.Linq.Expressions;
using Cherry.Agile.Data.Metadata;
using System.Reflection;
using Cherry.Agile.Data.Object.Metadata;
using Cherry.Agile.Data.Metadata.Interpreter;


namespace Cherry.Agile.Data.Metadata
{
    
    internal sealed class MemberInitExpressionParser<T> :IExpressionParser
        where T:class
    {
        #region IExpressionParser Members

        Expression mExpression;
        /// <summary>
        /// <see cref="Cherry.Agile.Data.Metadata.IExpressionParser"/>
        /// </summary>
        public System.Linq.Expressions.Expression Expression
        {
            get
            {
                return mExpression;
            }
            set
            {
                mExpression = value;
            }
        }
        
        public string ParseExpression(string containerName)
        {
            Expression<Func<T, T>> inner = Expression as Expression<Func<T, T>>;
            if (inner != null)
            {
                MemberInitExpression initExpression = inner.Body as MemberInitExpression;
                if (initExpression != null)
                {
                    List<MemberAssignment> memberAssignments = (from m in initExpression.Bindings.OfType<MemberAssignment>() select m).ToList();
                    
                    var result = (from m in initExpression.Bindings.OfType<MemberAssignment>()
                                  select new { PropertyName = m.Member.Name, Value = ParseValueExpression(containerName,m.Expression) }).ToList();
                    var map = MetadataAccessor.GetTableNameByEdmType<T>(containerName);
                    
                    StringBuilder sb = new StringBuilder();
                    sb.Append("SET  ").
                    Append( map[result[0].PropertyName ])
                    .Append(" =")
                    .Append(result[0].Value.Replace("\"","'"));

                    for (int i = 1; i < result.Count; i++)
                    {
                        sb.Append(",");
                        sb.Append(map[result[i].PropertyName]);//MetadataAccessor.GetColumnNameByEdmProperty<T>(result[i].PropertyName));
                        sb.Append("=");
                        sb.Append(result[i].Value.Replace("\"","'"));
                    }
                    return sb.ToString();
                }
                else
                    throw new InvalidOperationException("Expression is not  a valid expresion");
            }
            else
                throw new InvalidOperationException("Expression is not  a valid expresion");
        }

        #endregion

        #region Private Methods

        private string ParseValueExpression( string containerName,Expression expression)
        {
            if (expression is ConstantExpression)
                return InterpreterFactory.GetInterpreter(typeof(ConstantExpression)).InterpreteExpression<T>(containerName, expression);
            else if (expression is MemberExpression)
            {
                var exp = expression as MemberExpression;
                return InterpreterFactory.GetInterpreter(typeof(MemberExpression)).InterpreteExpression<T>(containerName, exp);
            }
            else if (expression is UnaryExpression)
            {
                Expression operandExpression = ((UnaryExpression)expression).Operand;
                if (operandExpression is MemberExpression)
                {
                    return InterpreterFactory.GetInterpreter(typeof(MemberExpression)).InterpreteExpression<T>(containerName, operandExpression);
                }
                else if (operandExpression is NewExpression)
                {
                    return InterpreterFactory.GetInterpreter(typeof(NewExpression)).InterpreteExpression<T>(containerName, operandExpression);
                }
                else
                    throw new InvalidOperationException("Invalid Expression in SET Expression");
            }
            else
            {
                 
                throw new InvalidOperationException("Invalid Expression in SET Expression");
            }
        }
        #endregion
    }
}
